package io.pumelo.wxjump;

import static io.pumelo.wxjump.TemplateMatch.*;
import static org.bytedeco.javacpp.opencv_core.*;
import static org.bytedeco.javacpp.opencv_imgcodecs.cvLoadImage;
import static org.bytedeco.javacpp.opencv_imgcodecs.cvSaveImage;
import static org.bytedeco.javacpp.opencv_imgproc.cvCanny;

import org.bytedeco.javacv.JavaCV;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.awt.Point;
import java.io.IOException;
import java.nio.ByteBuffer;

@Service
public class AutoJumpService {

    @Autowired
    private Runtime runtime;

    private int chessHeight;
    private int chessWidth;
    private IplImage chessImage;
    private boolean gameOver = false;

    /**
     * 初始化棋子
     */
    @PostConstruct
    public void init(){
        //读取棋子图片,获取形状，height width
        IplImage rawImage;
        rawImage = cvLoadImage("chess.png");
        if(rawImage == null){
            System.out.println("棋子图片丢失");
            return;
        }
        chessImage = rawImage;
        CvSize size = rawImage.cvSize();
        chessHeight = size.height();
        chessWidth = size.width();

//        findChess(getScreenShot());
//        findNextTop(getScreenShot());
//        find();

    }

    public boolean isGameOver() {
        return gameOver;
    }

    /**
     * 通过adb获取截图
     * 并且拉取到本地
     */
    public IplImage getScreenShot(){
        IplImage target;
        String imgName = "autojump_" + System.currentTimeMillis()+".png";
        try {
            runtime.exec("adb shell screencap -p /sdcard/"+imgName).waitFor();
            runtime.exec("adb pull /sdcard/"+imgName).waitFor();
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
        target = cvLoadImage(imgName);
        if(target == null){
            System.out.println("读取截图失败");
            return null;
        }
        return target;
    }

    /**
     * 寻找棋子的位置
     */
    public Point findChess(IplImage targetImage){
        return fixChessOffSet(match(chessImage,targetImage));
    }

    /**
     * 修正棋子的位置
     * @param matchResult
     * @return
     */
    private Point fixChessOffSet(MatchResult matchResult){
        if(matchResult.score<0.6){
            System.out.println("game over");
            gameOver = true;
            return null;
        }
        return new Point(matchResult.x+chessImage.width()/2-3,matchResult.y+chessImage.height()-15);
    }

    /**
     * 获取目标位置的最上顶点
     */
    public Point findNextTop(IplImage target,Point chessLoc){
        IplImage result = cvCreateImage(target.cvSize(),target.depth(),1);
        cvCanny(target,result,50,100);
        ByteBuffer buffer = result.getByteBuffer();
        byte[] bb = new byte[buffer.remaining()];
        buffer.get(bb);//获取byte数据
        int width=result.width();
        int height=result.height();
        int widthStep=result.widthStep();
        int nChannel=result.nChannels();
        int skipRows = 200;// 跳过行数
        for(int y=skipRows;y<height;y++){
            for(int x=0;x<width;x++){
                int index=widthStep*y+nChannel*x;
                if(bb[index] == -1 && !isOnChessArea(chessLoc,x,y)){
                    System.out.println("["+x+","+y+"]");
                    return new Point(x,y);
                }
            }
        }
        cvReleaseImage(result);
        return null;
    }

    /**
     * 图像识别测试函数
     * 仅用于定位棋子和目标坐标，并且可视化为图片
     * @return
     */
    public Point find(){
        String imgName = "autojump_1515657713727.png";
        IplImage target;
        target = cvLoadImage(imgName);
        Point chessLoc = findChess(target);
        System.out.println("棋子修正后的坐标="+chessLoc);
        IplImage result = cvCreateImage(target.cvSize(),target.depth(),1);
        cvCanny(target,result,50,100);
        ByteBuffer buffer = result.getByteBuffer();

        byte[] bb = new byte[buffer.remaining()];
        buffer.get(bb);//获取byte数据
        int width=result.width();
        int height=result.height();
        int widthStep=result.widthStep();
        int nChannel=result.nChannels();
        int skipRows = 200;// 跳过行数
        boolean isFirst =  true;
        int pos = -1;
        for(int y=skipRows;y<height;y++){
            for(int x=0;x<width;x++){
                int index=widthStep*y+nChannel*x;
                if(bb[index] == 0){
                    if(index != pos){
                        bb[index] = -1;//无关要素全部填充白色
                    }
                }else {
                    //判断是否和棋子重叠
                    if(isOnChessArea(chessLoc,x,y)){
                        continue;
                    }

                    if(isFirst){
                        bb[index] = 0;//第一次扫描到的顶点坐标
                        pos = widthStep*(y+20)+nChannel*x;//临时的目标坐标
                        bb[pos] = 0;
                        isFirst = false;
                    }
                }
            }
        }
        bb[widthStep*chessLoc.y+nChannel*chessLoc.x] = 0;//棋子坐标
        result.getByteBuffer().put(bb);
        cvSaveImage("processed.png",result);
        cvReleaseImage(result);
        return null;
    }

    public boolean isOnChessArea(Point chessLoc,int x,int y){
        return x >= chessLoc.x - chessWidth / 2
                && x <= chessLoc.x + chessWidth / 2
                && y <= chessLoc.y && y >= chessLoc.y - chessHeight;
    }

    /**
     * 起跳
     * @Fixme 起跳的按压时间需要根据屏幕的分辨率缩放处理
     * @param distance
     */
    public void jump(double distance){
        int pressTime =(int) (distance * 1.9);
        try {
            runtime.exec("adb shell input swipe 643 800 643 800 "+pressTime).waitFor();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
